<template>
  <el-dialog
    title="文件管理"
    width="963px"
    append-to-body
    v-bind="$attrs"
    @close="onClose"
    v-drag-zoom
  >
    <el-container class="app-container">
      <el-aside width="200px">
        <el-card>
          <el-input
            placeholder="请输入文件夹名称"
            v-model="filterFolder"
            clearable
            size="small"
          >
          </el-input>
          <el-tree
            class="folder-tree"
            :data="folderList"
            :props="defaultProps"
            default-expand-all
            :filter-node-method="filterNode"
            :expand-on-click-node="false"
            @node-click="handleCurrentFolder"
            :highlight-current="true"
            :default-expand-all="true"
            check-strictly
            node-key="id"
            ref="tree"
          >
              <span slot-scope="{ node,data }">
                 <i class="el-icon-folder" style="padding-left: 3px"></i> {{ node.label }}
              </span>
          </el-tree>
        </el-card>
      </el-aside>
      <el-container width="763px">
        <el-header>
          <el-card v-show="showSearch">
            <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
              <el-form-item label="文件名称" prop="fileName">
                <el-input
                  v-model="queryParams.fileName"
                  placeholder="请输入文件名称"
                  clearable
                  @keyup.enter.native="handleQuery"
                />
              </el-form-item>
              <el-form-item>
                <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
                <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
              </el-form-item>
            </el-form>
            <el-row :gutter="10" class="mb8">
              <el-tooltip
                class="item"
                effect="dark"
                :content="'仅支持大小不超过' + fileSize + 'MB格式为' + fileType.join('/') + '的文件'"
                placement="bottom-start"
              >
                <div style="display: inline-block">
                  <el-button
                    type="primary"
                    plain
                    icon="el-icon-upload2"
                    size="mini"
                    v-show="!dvShowUploadBtn"
                    class="upload-file-uploader"
                    @click="checkUpload"
                  >上传文件</el-button>
                  <el-upload
                    multiple
                    :action="uploadFileUrl"
                    :before-upload="handleBeforeUpload"
                    :file-list="uploadFileList"
                    :limit="limit"
                    :on-error="handleUploadError"
                    :on-exceed="handleExceed"
                    :on-success="handleUploadSuccess"
                    :on-change="getFileList"
                    :show-file-list="false"
                    :headers="headers"
                    class="upload-file-uploader"
                    ref="upload"
                    v-show="dvShowUploadBtn"
                  >
                    <!-- 上传按钮 -->
                    <el-button
                      type="primary"
                      plain
                      icon="el-icon-upload2"
                      size="mini"
                    >上传文件</el-button>
                  </el-upload>
                </div>
              </el-tooltip>
              <el-tooltip
                class="item"
                effect="dark"
                :content="'仅支持大小不超过' + fileSize + 'MB格式为' + fileType.join('/') + '的文件'"
                placement="bottom-start"
              >
                <div style="display: inline-block">
                  <el-button
                    type="primary"
                    plain
                    icon="el-icon-upload2"
                    size="mini"
                    @click="handleImageCopper"
                    v-if="dvShowCropperBtn"
                  >上传并裁剪图片</el-button>
                </div>
              </el-tooltip>
              <el-button style="margin-left: 10px" type="primary" size="mini" @click="handleConfirm">确定选择</el-button>
            </el-row>
          </el-card>
        </el-header>
        <el-main>
          <el-card class="table-card">
            <div class="image-container">
              <div class="show-image" id="show-image-container">
                <template v-for="(item, index) in fileList">
                  <div class="block" :id="'block' + index">
                    <el-image
                      v-if="['mp3','wma', 'flac'].includes(item.fileExtName)"
                      @click="handleSelectChange(item, index)"
                      :class="{ 'image-info': selectFileUrls.includes(item.fileUrl) }"
                      style="width: 140px; height: 140px;"
                      :src="require('@/assets/images/music.jpg')"
                      fit="cover"
                    ></el-image>
                    <el-image
                      v-else
                      @click="handleSelectChange(item, index)"
                      :class="{ 'image-info': selectFileUrls.includes(item.fileUrl) }"
                      style="width: 140px; height: 140px;"
                      :src="item.fileUrl"
                      fit="cover"
                    ></el-image>
                    <span class="demonstration">{{ item.fileName }}</span>
                    <!-- 右键菜单区域 -->
                    <context-menu
                      :target="contextMenuTarget[index]"
                      :show="contextMenuVisible[index]"
                      @update:show="(show) => (contextMenuVisible[index] = show)"
                      class="right-menu"
                    >
                      <a href="javascript:;" @click="handlePreview(item)">
                        <i class="el-icon-view"></i><b> {{ ['mp3','wma', 'flac'].includes(item.fileExtName) ? '播放音乐' : '查看图片' }}</b>
                      </a>
                      <a v-if="!['mp3','wma', 'flac'].includes(item.fileExtName)" href="javascript:;" @click="handleImageCopper(item)">
                        <i class="el-icon-scissors"></i><b> 裁剪图片</b>
                      </a>
                      <!-- <a href="javascript:;" @click="handleDelete(item)">
                        <i class="el-icon-delete"></i><b> 删除文件</b>
                        </a> -->
                    </context-menu>
                  </div>
                  <br v-if="(index + 1) % 5 === 0"/>
                </template>
              </div>
            </div>
            <pagination
              v-show="total>0"
              :total="total"
              :page.sync="queryParams.pageNum"
              :limit.sync="queryParams.pageSize"
              @pagination="getFileList"
            />
          </el-card>
        </el-main>
      </el-container>
      <!-- 预览  -->
      <el-dialog
        :visible.sync="previewVisible"
        :title="previewFile.fileName"
        width="70%"
        class="preview-dialog"
        :modal-append-to-body="false"
        :append-to-body="true"
        v-drag-zoom
      >
        <div v-if="['mp3','wma', 'flac'].includes(previewFile.fileExtName)" class="preview-container">
          <el-image
            v-if="['mp3','wma', 'flac'].includes(previewFile.fileExtName)"
            style="width: 200px; height: 200px;"
            :src="require('@/assets/images/music.jpg')"
            :fit="'cover'"
          >{{ previewFile.fileName }}</el-image>
          <div class="audio-player">{{ previewFile.fileName }}</div>
          <audio class="audio-player" :src="previewFile.fileUrl" :autoplay="previewVisible" controls="controls" />
        </div>
        <div v-else class="preview-container">
          <el-image
            :src="previewFile.fileUrl"
            :fit="'contain'"
            style="margin: auto"
          />
        </div>
      </el-dialog>
      <!-- 图片裁剪弹框 -->
      <base-image-cropper :visible.sync="imageCopperVisible" :image-url="cropperImageUrl" :file-path="uploadFolder" @afterUpload="afterUpload" :fixed-box="false"/>
    </el-container>
  </el-dialog>
</template>
<script>
import { listFolder } from '@/api/file/folder'
import { listFile } from '@/api/file/file'
import { getToken, getUserId } from "@/utils/auth";
import BaseImageCropper from '@/components/BaseImageCropper/index.vue'
import Pagination from "@/components/Pagination/index.vue";
import { handleTree } from "@/utils/lemon";
import {Message, MessageBox} from "element-ui";
import store from "@/store";

export default {
  name: 'fileSelect',
  components: {
    Pagination,
    BaseImageCropper
  },
  props: {
    fileExtName: {
      type: Array,
      default: () => ["doc", "docx", "xls", "xlsx","ppt", "txt", "pdf", 'mp3','wma',
        'flac', 'jpeg', 'jpg', 'png', 'zip', 'rar', 'gif'],
    },
    dvMultiFile: {
      type: Boolean,
      default: false
    },
    // 大小限制(MB)
    fileSize: {
      type: Number,
      default: 40,
    }
  },
  watch: {
    filterFolder(val) {
      this.$refs.tree.filter(val);
    },
    rowIndex(newVal, oldVal) {
      this.rightClickEvent(newVal);
    }
  },
  data() {
    return {
      showVisible: true,
      filterFolder: '',
      fileList: [],
      defaultProps: {
        children: 'children',
        label: 'folderName'
      },
      folderList: [],
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        fileName: '',
        userId: getUserId(),
        folder: '',
        fileExtName: ''
      },
      showSearch: true,
      // 是否展开，默认全部展开
      isExpandAll: true,
      // 重新渲染表格状态
      refreshTable: true,
      // 选中的文件id列表
      fileIds: [],
      loading: true,
      // 总条数
      total: 0,
      // 用户列表
      userOptions: [],
      // 选中的文件
      selectFileUrls: [],
      // 预览弹框显示状态
      previewVisible: false,
      // 预览文件url
      previewFile: {},
      /** 文件上传属性 */
      // 上传的文件列表回显数据
      uploadFileList: [],
      // 文件上传成功列表
      resultList: [],
      // 上传文件数量记录
      number: 0,
      // 文件上传接口
      baseUploadUrl: process.env.VUE_APP_BASE_API + "/file/file/uploadWeb?path=",
      // 上传文件的服务器完整地址
      uploadFileUrl: '',
      // 上传的文件夹
      uploadFolder: '',
      // 上传文件请求头
      headers: {
        Authorization: "Bearer " + getToken(),
      },
      // 允许上传的文件类型
      fileType: this.fileExtName,
      // 单次允许上传的最大文件数量
      limit: 5,
      // 是否展示图片裁剪弹框
      imageCopperVisible: false,
      // 图片文件类型
      imageFileType: ["png", "jpg", "jpeg", 'blob'],
      /** 右键菜单 */
      contextMenuTarget: [],
      // 右键菜单显示状态
      contextMenuVisible: [],
      // 文件类型
      dvFileType: '',
      // 当前数据行号
      rowIndex: null,
      // 裁剪的图片地址
      cropperImageUrl: '',
      // 裁剪按钮显示状态
      dvShowCropperBtn: false,
      // 上传按钮显示状态
      dvShowUploadBtn: false
    }
  },
  async created() {
    await this.getFolderList();
    await this.getFileList();
    const that = this;
    this.dvShowCropperBtn = this.fileExtName.every(function(item) {
      return that.imageFileType.indexOf(item) !== -1;
    });
  },
  methods: {
    /** 文件夹过滤 */
    filterNode(value, data) {
      if (!value) return true;
      return data.folderName.indexOf(value) !== -1;
    },
    /** 查询文件夹列表 */
    async getFolderList() {
      listFolder().then(response => {
        this.folderList = handleTree(response.data, "folderCode", "parentCode", null);
      });
    },
    /** 获取文件列表 */
    async getFileList() {
      this.loading = true;
      this.queryParams.fileExtName = this.fileExtName.join(',')
      listFile(this.queryParams).then(res => {
        this.contextMenuTarget = [];
        this.contextMenuVisible = [];
        this.fileList = res.rows;
        this.total = res.total;
        this.loading = false
      })
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getFileList();
    },
    /** 处理选择的文件夹 */
    handleCurrentFolder(data, node, curr) {
      this.resetForm("queryForm");
      this.queryParams.folder = data.pathCode;
      this.uploadFolder = this.queryParams.folder;
      this.uploadFileUrl = this.baseUploadUrl + this.uploadFolder;
      this.selectFileUrls = [];
      this.dvShowUploadBtn = true;
      this.handleQuery();
    },
    /** 重置 */
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
    /** 预览文件 */
    handleView(row) {
      window.open(row.fileUrl);
    },
    /** 选中文件处理 */
    handleSelectChange(item, index) {
      if (this.dvMultiFile) {
        if (this.selectFileUrls.includes(item.fileUrl)) {
          this.selectFileUrls.splice(this.selectFileUrls.indexOf(item.fileUrl), 1);
        } else {
          this.selectFileUrls.push(item.fileUrl)
        }
      } else {
        this.selectFileUrls = [];
        this.selectFileUrls.push(item.fileUrl);
      }
      this.dvFileType = this.imageFileType.includes(item.fileExtName) ? 'image' : 'music';
      this.rowIndex = index;
    },
    /** 右键事件 */
    rightClickEvent(index) {
      this.$nextTick(() => {
        // 挂载右键菜单
        this.contextMenuTarget[index] = document.querySelector('#block' + index);
        // 获取所有的 .blog ，循环监听右键事件
        const images = document.querySelectorAll('#block' + index + ' .el-image');
        images.forEach(i => {
          i.addEventListener('contextmenu', evt => {
            this.contextMenuVisible[index] = true;
            event.target.click();
          }, true);
        })
      })
    },
    /** 预览文件 */
    handlePreview(item) {
      this.previewFile = item
      this.previewVisible = true
    },
    /** 确定选择 */
    handleConfirm() {
      if (this.selectFileUrls.length > 0) {
        if (this.dvMultiFile) {
          this.$emit("setFileUrl", this.selectFileUrls);
        } else {
          this.$emit("setFileUrl", this.selectFileUrls[0]);
        }
      } else {
        this.$message.warning('请选择文件！')
      }
    },
    /** 关闭弹框 */
    onClose() {
      this.$emit('update:visible', false);
    },
    // 上传前校检格式和大小
    handleBeforeUpload(file) {
      if (this.queryParams.folder === '') {
        this.$modal.msgError("请选择上传的文件夹!");
        return false;
      }
      // 校检文件类型
      if (this.fileType) {
        let fileExtension = "";
        if (file.name.lastIndexOf(".") > -1) {
          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
        }
        const isTypeOk = this.fileType.some((type) => {
          if (file.type.indexOf(type) > -1) return true;
          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
          return false;
        });
        if (!isTypeOk) {
          this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
          return false;
        }
      }
      // 校检文件大小
      if (this.fileSize) {
        const isLt = file.size / 1024 / 1024 < this.fileSize;
        if (!isLt) {
          this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`);
          return false;
        }
      }
      this.$modal.loading("正在上传文件，请稍候...");
      this.number++;
      return true;
    },
    // 文件个数超出
    handleExceed() {
      this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
      this.uploadFileList = [];
      this.number = 0;
    },
    // 上传失败
    handleUploadError(err) {
      this.$modal.msgError("上传文件失败，请重试");
      this.$modal.closeLoading()
    },
    // 上传成功回调
    handleUploadSuccess(res) {

      const code = res.code;
      const msg = res.msg;
      if (code === 401) {
        MessageBox.confirm('登录状态已过期，您可以继续留在该页面，或重新登录', '系统提示', {
              confirmButtonText: '重新登录',
              cancelButtonText: '取消',
              type: 'warning'
            }
        ).then(() => {
          store.dispatch('LogOut').then(() => {
            location.href = '/index';
          })
        })
      } else if (code === 500) {
        Message({
          message: msg,
          type: 'error'
        })
        this.uploadFileList = [];
        this.number = 0;
      } else if (code !== 200) {
        Notification.error({
          title: msg
        })
        this.uploadFileList = [];
        this.number = 0;
      } else {
        this.resultList.push({ name: res.data.url, url: res.data.url });
        if (this.resultList.length === this.number) {
          this.uploadFileList = [];
          this.resultList = [];
          this.number = 0;
          this.$modal.msgSuccess("上传文件成功！");
        }
      }
      this.$modal.closeLoading();
    },
    /** 打开图片裁剪弹框 */
    handleImageCopper(item) {
      if (this.queryParams.folder === '') {
        this.$modal.msgError("请选择上传的文件夹!");
      } else {
        this.cropperImageUrl = item?.fileUrl;
        this.imageCopperVisible = true;
      }
    },
    /** 上传提示 */
    checkUpload() {
      this.$modal.msgError("请选择上传的文件夹!");
    },
    /** 文件上传成功之后的回调 */
    afterUpload(url) {
      this.imageCopperVisible = false;
      this.getFileList();
    },
    /** 表单重置 */
    resetForm(refName) {
      if (this.$refs[refName]) {
        this.$refs[refName].resetFields();
      }
    }
  }
}
</script>
<style lang="scss" scoped>
::v-deep .el-dialog__body {
  padding: 20px 10px 10px 20px !important;
  .app-container {
    padding: 0 !important;
    height: calc(100vh - 434px);
    .el-tree {
      height: calc(100vh - 498px);
    }
    .el-header {
      height: auto !important;
      padding-right: 0px !important;
    }
    .el-aside {
      padding: 0px !important;
      box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
      -webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      margin-bottom: 8px !important;
      .el-card__body {
        padding-bottom: 0 !important;
      }
    }
    .el-card__body {
      padding: 10px !important;
    }
    .el-divider {
      margin: 0px !important;
    }
    .el-main {
      padding-top: 0px !important;
      padding-right: 0px !important;
      overflow: hidden;
      .pagination-container {
        margin-bottom: 25px !important;
        margin-top: 0 !important;
      }
    }
  }
  .folder-tree {
    margin-top: 10px;
  }
  .image-container {
    height: calc(100vh - 628px);
    overflow: hidden;
    .show-image {
      display: flex;
      justify-content: left;
      flex-wrap: wrap;
      max-height: calc(100vh - 628px);
      overflow-y: scroll;
      .block {
        margin: 10px;
        .demonstration {
          display: block;
          max-width: 150px;
          overflow: hidden;
        }
        .image-info {
          width: 140px;
          height: 140px;
          color: #4abe84;
          box-shadow: 0 2px 7px 0 rgba(85, 110, 97, 0.35);
          border-radius: 7px;
          border: 1px solid rgba(74, 190, 132, 1);
        }
        .image-info:before {
          content: "";
          position: absolute;
          right: 0;
          bottom: 0;
          border: 17px solid #4abe84;
          border-top-color: transparent;
          border-left-color: transparent;
        }
        .image-info:after {
          content: "";
          width: 5px;
          height: 12px;
          position: absolute;
          right: 6px;
          bottom: 6px;
          border: 2px solid #fff;
          border-top-color: transparent;
          border-left-color: transparent;
          transform: rotate(45deg);
        }
      }
      .el-image {
        box-shadow: 0 2px 7px 0 rgba(85, 110, 97, 0.35);
        border-radius: 7px;
      }
    }
  }
  .preview-container {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    height: 100%;
    width: 100%;
    .audio-player {
      display: block;
    }
  }
  .upload-file-uploader {
    display: inline-block;
    margin-left: 10px;
    margin-right: 10px;
  }
}
.preview-dialog {
  z-index: 10000 !important;
  ::v-deep .el-dialog__body {
    height: calc(70vh - 60px) !important;
  }
}
.right-menu {
  font-size: 13px;
  position: fixed;
  background: rgba(255, 255, 255);
  border: solid 1px rgba(0,0,0,0.2);
  box-shadow: 0 0.5em 1em rgba(0,0,0,0.1) ;
  border-radius: 3px;
  z-index: 1500;
  display: none;
}
.right-menu a {
  width: 90px;
  height: 28px;
  line-height: 28px;
  text-align: center;
  color: #a45eff;
  display: block;
  text-decoration: none;
}
.right-menu a:hover {
  background: rgba(246, 240, 240, 0.84);
  color: #fa5e75;
}
</style>
